package com.interphone.beta.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.Charset;

import com.interphone.beta.Main;
import com.interphone.beta.stream.Stream;
import com.jcraft.jsch.Session;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

public class Communicator extends Thread {
	// Algo AA
	/*
	 * Debut Ouverture de la connexion Recuperation de l'IP et du port de la
	 * connexion Publication de l'IP et du port de la communication sur
	 * l'annuaire (site web) Attente de connexion (Mise en place IHM) Si
	 * connexion etablie alors Attente acceptation de la part de l'utilisateur
	 * (Mise en place IHM) Si l'utilisateur accepte Ouverture du flux audio de
	 * reception (thread) Envoi du port du flux audio de reception
	 * 
	 * Attente de reception du port du flux audio d'emission Reception du port
	 * du flux audio d'emission Ouverture du flux audio d'emission (thread)
	 * 
	 * Attente d'ordre de la part de l'utilisateur Tant que l'ordre recu n'est
	 * pas fin de communication Si ordre recu est "ouverture de porte" alors
	 * Procedure d'ouverture de porte Fin si Fin tant que Fin si Fin si
	 * Fermeture de la communication Fin
	 */
	private String ip;
	private int port;
	private Socket soc;
	private BufferedReader in;
	private PrintWriter out;
	private Main main;
	private boolean loop;
	private Stream mySendStream;
	private Stream myreceiveStream;
	private String TAG;
	private Session session;

	private static final int ERR = -1;
	private static final int GO = 0;
	private static final int CLOSE = 1;
	private static final int HB = 2;
	private static final int OPENDOOR = 3;
	private static final int OK = 4;

	public Communicator(Session session, Socket soc, final Main main) {
		this.TAG = this.getClass().toString();
		this.soc = soc;
		this.ip = soc.getInetAddress().toString();
		this.port = soc.getPort();
		this.main = main;
		this.main.setCom(this);
		this.session = session;
		Handler refresh = new Handler(Looper.getMainLooper());
		refresh.post(new Runnable() {
			public void run() {
				main.initAppel();
			}
		});
		try {
			in = new BufferedReader(new InputStreamReader(soc.getInputStream()));
			out = new PrintWriter(soc.getOutputStream());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void run() {
		try {
			
			loop=false;
			
			Log.d(TAG, "Envoie de GO : " + GO);
			out.println(GO);
			out.flush();

			// Attente du ok pour lancer la communication
			String[] rep = in.readLine().split(":");
			Log.d(TAG, rep.toString());

			// Reception d'une réponse correcte : infos OK
			if (rep != null && rep[0] != null && Integer.parseInt(rep[0]) == OK) {
				
				//Envoie des infos OK
				//String mess = OK + ":" + MyPublish.IP + ":" + MyPublish.SSID;
				String mess = OK + ":" + MyPublish.IP + ":" + "XX";
				Log.d(TAG, "Envoie de OK : " + mess);
				out.println(mess);
				out.flush();

				if (rep != null && rep[0] != null && rep[1] != null && rep[2] != null) {
					String ssid = MyPublish.SSID;
					ssid="XX";
					Log.d(TAG, "Infos OK :OK");

					if (rep[2].equals(ssid) && !rep[2].equals("null") && !ssid.equals("null")) {
						// On est dans le meme reseau WIFI
						Log.d(TAG, "WIFI");

						// Ouverture du flux audio de reception (thread)
						Log.d(TAG, "Lancement du stream entrant");
						this.myreceiveStream = new Stream();
						this.myreceiveStream.initReceiveStream();
						this.myreceiveStream.play();
						
						// Envoi du port du flux audio de reception
						while (this.myreceiveStream.getPort() == 0) {

						}
						int portR = this.myreceiveStream.getPort();
						Log.d(TAG, "Port de reception : " + portR);
						mess="infos:" + MyPublish.IP + "@" + portR;
						Log.d(TAG, "Envoie des infos : " + mess);
						out.println(mess);
						out.flush();

						// Attente de reception du port du flux audio d'emission
						// Reception du port du flux audio d'emission
						// Ouverture du flux audio d'emission (thread)
						mess = in.readLine();
						Log.d(TAG, mess);
						if (mess.split(":")[0].equalsIgnoreCase("infos")) {
							String myport = mess.split(":")[1].split("@")[1];
							String myip = mess.split(":")[1].split("@")[0];
							Log.d(TAG, "Port recu : " + mess.split(":")[1]);
							Log.d(TAG, "Lancement du stream sortant");
							this.mySendStream = new Stream();
							this.mySendStream.initSendStream(new String(myip.getBytes(), Charset.forName("UTF-8")), new String(myport.getBytes(), Charset.forName("UTF-8")));
							this.mySendStream.play();
							loop = true;
						} else {
							Log.d(TAG, "Erreur de protocol : " + mess);
							loop = false;
						}

					} else {
						// On est pas dans le meme reseau WIFI
						// Ouverture du flux audio d'emission afon de determiner
						// le port
						// depuis lequl on envoie.
						Log.d(TAG, "Lancement du stream sortant");
						this.mySendStream = new Stream();
						this.mySendStream.initSendStream(new String(new String("localhost").getBytes(), Charset.forName("UTF-8")), new String("8000".getBytes(), Charset.forName("UTF-8")));
						UDPServer udpS = new UDPServer();
						udpS.start();
						this.mySendStream.play();
						while (udpS.getPort() == null || udpS.getPort() == "0")
							;
						this.mySendStream.pause();

						// Création d'un client UDP depuis le port précédent
						// vers un serveur
						// qui renvoie le port et l'ip public
						BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
						DatagramSocket clientSocket = new DatagramSocket(Integer.valueOf(udpS.getPort()));
						InetAddress IPAddress = InetAddress.getByName(MyPublish.SERVER);
						byte[] sendData = new byte[1024];
						byte[] receiveData = new byte[1024];
						String sentence = inFromUser.readLine();
						sendData = sentence.getBytes();
						DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 8000);
						clientSocket.send(sendPacket);
						DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
						clientSocket.receive(receivePacket);
						String modifiedSentence = new String(receivePacket.getData());
						System.out.println("FROM SERVER:" + modifiedSentence);
						clientSocket.close();

						// Ouverture du flux audio de reception (thread)
						Log.d(TAG, "Lancement du stream entrant");
						this.myreceiveStream = new Stream();
						this.myreceiveStream.initReceiveStream();
						this.myreceiveStream.play();
						// Envoi du port du flux audio de reception
						while (this.myreceiveStream.getPort() == 0) {

						}
						int portR = this.myreceiveStream.getPort();
						Log.d(TAG, "Port de reception : " + portR);

						out.println("infos:" + MyPublish.IP + "@" + portR);
						out.flush();

						// Attente de reception du port du flux audio d'emission
						// Reception du port du flux audio d'emission
						// Ouverture du flux audio d'emission (thread)
						mess = in.readLine();
						Log.d(TAG, mess);
						if (mess.split(":")[0].equalsIgnoreCase("infos")) {
							String myport = mess.split(":")[1].split("@")[1];
							String myip = mess.split(":")[1].split("@")[0];
							Log.d(TAG, "Port recu : " + mess.split(":")[1]);
							Log.d(TAG, "Lancement du stream sortant");
							this.mySendStream = new Stream();
							this.mySendStream.initSendStream(new String(myip.getBytes(), Charset.forName("UTF-8")), new String(myport.getBytes(), Charset.forName("UTF-8")));
							this.mySendStream.play();
							loop = true;
						} else {
							Log.d(TAG, "Erreur de protocol : " + mess);
							loop = false;
						}
					}
				}
				
				while (loop) {
					int ordre = 0;
					String m = null;
					try {
						m = in.readLine();
						Log.d(TAG, "mess = " + m);
						if (m == null) {
							ordre = CLOSE;
						} else {
							ordre = Integer.parseInt(m);
						}

					} catch (NumberFormatException e) {
						ordre = ERR;
					}

					Log.d(TAG, "Ordre = " + ordre);

					switch (ordre) {
					case CLOSE:
						Log.d(TAG, "Reception Close : " + CLOSE);
						loop = false;
						main.myFinishAppel();
						break;
					case HB:
						Log.d(TAG, "Reception hb : " + HB);
						break;
					default:
						Log.d(TAG, "Ordre non compréhensible");
						break;
					}
				}
			}

			//Arret du flux sortant
			if(this.mySendStream!=null){
				this.mySendStream.pause();
				this.mySendStream.nativeFinalize();
			}

			//Arret du flux entrant
			if(this.myreceiveStream!=null){
				this.myreceiveStream.pause();
				this.myreceiveStream.nativeFinalize();
			}

			main.myFinishAppel();
			session.delPortForwardingR(this.myreceiveStream.getPort());
			Log.d(TAG, "Fin du thread");

		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.d(TAG, "Deco brutale1");
			decoBrutale();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			Log.d(TAG, "Deco brutale2");
			e.printStackTrace();
			decoBrutale();

		}

	}

	public void decoBrutale() {
		Handler refresh = new Handler(Looper.getMainLooper());
		refresh.post(new Runnable() {
			public void run() {
				Log.d(TAG, "Deco brutale : appel de myFinish");
				main.myFinishAppel();
			}
		});
	}

	/**
	 * 
	 */
	public void closeComm() {
		// TODO Auto-generated method stub
		setLoop(false);
		out.println(CLOSE);
		out.flush();
		out.close();

		try {
			in.close();
			soc.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public boolean isLoop() {
		return loop;
	}

	public void setLoop(boolean loop) {
		this.loop = loop;
	}

	public void openDoor() {
		// TODO Auto-generated method stub
		if (out != null) {
			out.println(OPENDOOR);
			out.flush();
		}
	}

	public Stream getMySendStream() {
		return mySendStream;
	}

	public void setMySendStream(Stream mySendStream) {
		this.mySendStream = mySendStream;
	}

	public Stream getMyreceiveStream() {
		return myreceiveStream;
	}

	public void setMyreceiveStream(Stream myreceiveStream) {
		this.myreceiveStream = myreceiveStream;
	}
}
